/*!
 * viewport-units-buggyfill v0.6.2
 * @web: https://github.com/rodneyrehm/viewport-units-buggyfill/
 * @author: Rodney Rehm - http://rodneyrehm.de/en/
 */

(function() {
    (function(root, factory) {
      'use strict';
      if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define([], factory);
      } else if (typeof exports === 'object') {
        // Node. Does not work with strict CommonJS, but
        // only CommonJS-like enviroments that support module.exports,
        // like Node.
        module.exports = factory();
      } else {
        // Browser globals (root is window)
        root.viewportUnitsBuggyfill = factory();
      }
    }(this, function() {
      'use strict';
      /* global document, window, navigator, location, XMLHttpRequest, XDomainRequest, CustomEvent */
  
      var initialized = false;
      var options;
      var userAgent = window.navigator.userAgent;
      var viewportUnitExpression = /([+-]?[0-9.]+)(vh|vw|vmin|vmax)/g;
      var urlExpression = /(https?:)?\/\//
      var forEach = [].forEach;
      var dimensions;
      var declarations;
      var styleNode;
      var isBuggyIE = /MSIE [0-9]\./i.test(userAgent);
      var isOldIE = /MSIE [0-8]\./i.test(userAgent);
      var isOperaMini = userAgent.indexOf('Opera Mini') > -1;
  
      var isMobileSafari = /(iPhone|iPod|iPad).+AppleWebKit/i.test(userAgent) && (function() {
        // Regexp for iOS-version tested against the following userAgent strings:
        // Example WebView UserAgents:
        // * iOS Chrome on iOS8: "Mozilla/5.0 (iPad; CPU OS 8_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) CriOS/39.0.2171.50 Mobile/12B410 Safari/600.1.4"
        // * iOS Facebook on iOS7: "Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_1 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Mobile/11D201 [FBAN/FBIOS;FBAV/12.1.0.24.20; FBBV/3214247; FBDV/iPhone6,1;FBMD/iPhone; FBSN/iPhone OS;FBSV/7.1.1; FBSS/2; FBCR/AT&T;FBID/phone;FBLC/en_US;FBOP/5]"
        // Example Safari UserAgents:
        // * Safari iOS8: "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4"
        // * Safari iOS7: "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A4449d Safari/9537.53"
        var iOSversion = userAgent.match(/OS (\d+)/);
        // viewport units work fine in mobile Safari and webView on iOS 8+
        return iOSversion && iOSversion.length > 1 && parseInt(iOSversion[1]) < 10;
      })();
  
      var isBadStockAndroid = (function() {
        // Android stock browser test derived from
        // http://stackoverflow.com/questions/24926221/distinguish-android-chrome-from-stock-browser-stock-browsers-user-agent-contai
        var isAndroid = userAgent.indexOf(' Android ') > -1;
        if (!isAndroid) {
          return false;
        }
  
        var isStockAndroid = userAgent.indexOf('Version/') > -1;
        if (!isStockAndroid) {
          return false;
        }
  
        var versionNumber = parseFloat((userAgent.match('Android ([0-9.]+)') || [])[1]);
        // anything below 4.4 uses WebKit without *any* viewport support,
        // 4.4 has issues with viewport units within calc()
        return versionNumber <= 4.4;
      })();
  
      // added check for IE10, IE11 and Edge < 20, since it *still* doesn't understand vmax
      // http://caniuse.com/#feat=viewport-units
      if (!isBuggyIE) {
        isBuggyIE = !!navigator.userAgent.match(/MSIE 10\.|Trident.*rv[ :]*1[01]\.| Edge\/1\d\./);
      }
  
      // Polyfill for creating CustomEvents on IE9/10/11
      // from https://github.com/krambuhl/custom-event-polyfill
      try {
        // eslint-disable-next-line no-new, no-use-before-define
        new CustomEvent('test');
      } catch (e) {
        var CustomEvent = function(event, params) {
          var evt;
          params = params || {
            bubbles: false,
            cancelable: false,
            detail: undefined,
          };
  
          evt = document.createEvent('CustomEvent');
          evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
          return evt;
        };
        CustomEvent.prototype = window.Event.prototype;
        window.CustomEvent = CustomEvent; // expose definition to window
      }
  
      function debounce(func, wait) {
        var timeout;
        return function() {
          var context = this;
          var args = arguments;
          var callback = function() {
            func.apply(context, args);
          };
  
          clearTimeout(timeout);
          timeout = setTimeout(callback, wait);
        };
      }
  
      // from http://stackoverflow.com/questions/326069/how-to-identify-if-a-webpage-is-being-loaded-inside-an-iframe-or-directly-into-t
      function inIframe() {
        try {
          return window.self !== window.top;
        } catch (e) {
          return true;
        }
      }
  
      function initialize(initOptions) {
        if (initialized) {
          return;
        }
  
        if (initOptions === true) {
          initOptions = {
            force: true,
          };
        }
  
        options = initOptions || {};
        options.isMobileSafari = isMobileSafari;
        options.isBadStockAndroid = isBadStockAndroid;
  
        if (options.ignoreVmax && !options.force && !isOldIE) {
          // modern IE (10 and up) do not support vmin/vmax,
          // but chances are this unit is not even used, so
          // allow overwriting the "hacktivation"
          // https://github.com/rodneyrehm/viewport-units-buggyfill/issues/56
          isBuggyIE = false;
        }
  
        if (isOldIE || (!options.force && !isMobileSafari && !isBuggyIE && !isBadStockAndroid && !isOperaMini && (!options.hacks || !options.hacks.required(options)))) {
          // this buggyfill only applies to mobile safari, IE9-10 and the Stock Android Browser.
          if (window.console && isOldIE) {
            console.info('viewport-units-buggyfill requires a proper CSSOM and basic viewport unit support, which are not available in IE8 and below');
          }
  
          return {
            init: function() {},
          };
        }
  
        // fire a custom event that buggyfill was initialize
        window.dispatchEvent(new CustomEvent('viewport-units-buggyfill-init'));
  
        options.hacks && options.hacks.initialize(options);
  
        initialized = true;
        styleNode = document.createElement('style');
        styleNode.id = 'patched-viewport';
        document[options.appendToBody ? 'body' : 'head'].appendChild(styleNode);
  
        // Issue #6: Cross Origin Stylesheets are not accessible through CSSOM,
        // therefore download and inject them as <style> to circumvent SOP.
        importCrossOriginLinks(function() {
          var _refresh = debounce(refresh, options.refreshDebounceWait || 100);
          // doing a full refresh rather than updateStyles because an orientationchange
          // could activate different stylesheets
          window.addEventListener('orientationchange', _refresh, true);
          // orientationchange might have happened while in a different window
          window.addEventListener('pageshow', _refresh, true);
  
          if (options.force || isBuggyIE || inIframe()) {
            window.addEventListener('resize', _refresh, true);
            options._listeningToResize = true;
          }
  
          options.hacks && options.hacks.initializeEvents(options, refresh, _refresh);
  
          refresh();
        });
      }
  
      function updateStyles() {
        styleNode.textContent = getReplacedViewportUnits();
        // move to the end in case inline <style>s were added dynamically
        styleNode.parentNode.appendChild(styleNode);
        // fire a custom event that styles were updated
        window.dispatchEvent(new CustomEvent('viewport-units-buggyfill-style'));
      }
  
      function refresh() {
        if (!initialized) {
          return;
        }
  
        findProperties();
  
        // iOS Safari will report window.innerWidth and .innerHeight as 0 unless a timeout is used here.
        // TODO: figure out WHY innerWidth === 0
        setTimeout(function() {
          updateStyles();
        }, 1);
      }
  
      // http://stackoverflow.com/a/23613052
      function processStylesheet(ss) {
        // cssRules respects same-origin policy, as per
        // https://code.google.com/p/chromium/issues/detail?id=49001#c10.
        try {
          if (!ss.cssRules) { return; }
        } catch (e) {
          if (e.name !== 'SecurityError') { throw e; }
          return;
        }
        // ss.cssRules is available, so proceed with desired operations.
        var rules = [];
        for (var i = 0; i < ss.cssRules.length; i++) {
          var rule = ss.cssRules[i];
          rules.push(rule);
        }
        return rules;
      }
  
      function findProperties() {
        declarations = [];
        forEach.call(document.styleSheets, function(sheet) {
          var cssRules = processStylesheet(sheet);
  
          if (!cssRules || sheet.ownerNode.id === 'patched-viewport' || sheet.ownerNode.getAttribute('data-viewport-units-buggyfill') === 'ignore') {
            // skip entire sheet because no rules are present, it's supposed to be ignored or it's the target-element of the buggyfill
            return;
          }
  
          if (sheet.media && sheet.media.mediaText && window.matchMedia && !window.matchMedia(sheet.media.mediaText).matches) {
            // skip entire sheet because media attribute doesn't match
            return;
          }
  
          forEach.call(cssRules, findDeclarations);
        });
  
        return declarations;
      }
  
      function findDeclarations(rule) {
        if (rule.type === 7) {
          var value;
  
          // there may be a case where accessing cssText throws an error.
          // I could not reproduce this issue, but the worst that can happen
          // this way is an animation not running properly.
          // not awesome, but probably better than a script error
          // see https://github.com/rodneyrehm/viewport-units-buggyfill/issues/21
          try {
            value = rule.cssText;
          } catch (e) {
            return;
          }
  
          viewportUnitExpression.lastIndex = 0;
          if (viewportUnitExpression.test(value) && !urlExpression.test(value)) {
            // KeyframesRule does not have a CSS-PropertyName
            declarations.push([rule, null, value]);
            options.hacks && options.hacks.findDeclarations(declarations, rule, null, value);
          }
  
          return;
        }
  
        if (!rule.style) {
          if (!rule.cssRules) {
            return;
          }
  
          forEach.call(rule.cssRules, function(_rule) {
            findDeclarations(_rule);
          });
  
          return;
        }
  
        forEach.call(rule.style, function(name) {
          var value = rule.style.getPropertyValue(name);
          // preserve those !important rules
          if (rule.style.getPropertyPriority(name)) {
            value += ' !important';
          }
  
          viewportUnitExpression.lastIndex = 0;
          if (viewportUnitExpression.test(value)) {
            declarations.push([rule, name, value]);
            options.hacks && options.hacks.findDeclarations(declarations, rule, name, value);
          }
        });
      }
  
      function getReplacedViewportUnits() {
        dimensions = getViewport();
  
        var css = [];
        var buffer = [];
        var open;
        var close;
  
        declarations.forEach(function(item) {
          var _item = overwriteDeclaration.apply(null, item);
          var _open = _item.selector.length ? (_item.selector.join(' {\n') + ' {\n') : '';
          var _close = new Array(_item.selector.length + 1).join('\n}');
  
          if (!_open || _open !== open) {
            if (buffer.length) {
              css.push(open + buffer.join('\n') + close);
              buffer.length = 0;
            }
  
            if (_open) {
              open = _open;
              close = _close;
              buffer.push(_item.content);
            } else {
              css.push(_item.content);
              open = null;
              close = null;
            }
  
            return;
          }
  
          if (_open && !open) {
            open = _open;
            close = _close;
          }
  
          buffer.push(_item.content);
        });
  
        if (buffer.length) {
          css.push(open + buffer.join('\n') + close);
        }
  
        // Opera Mini messes up on the content hack (it replaces the DOM node's innerHTML with the value).
        // This fixes it. We test for Opera Mini only since it is the most expensive CSS selector
        // see https://developer.mozilla.org/en-US/docs/Web/CSS/Universal_selectors
        if (isOperaMini) {
          css.push('* { content: normal !important; }');
        }
  
        return css.join('\n\n');
      }
  
      function overwriteDeclaration(rule, name, value) {
        var _value;
        var _selectors = [];
  
        _value = value.replace(viewportUnitExpression, replaceValues);
  
        if (options.hacks) {
          _value = options.hacks.overwriteDeclaration(rule, name, _value);
        }
  
        if (name) {
          // skipping KeyframesRule
          _selectors.push(rule.selectorText);
          _value = name + ': ' + _value + ';';
        }
  
        var _rule = rule.parentRule;
        while (_rule) {
          if (_rule.media) {
            _selectors.unshift('@media ' + _rule.media.mediaText);
          } else if (_rule.conditionText) {
            _selectors.unshift('@supports ' + _rule.conditionText);
          }
  
          _rule = _rule.parentRule;
        }
  
        return {
          selector: _selectors,
          content: _value,
        };
      }
  
      function replaceValues(match, number, unit) {
        var _base = dimensions[unit];
        var _number = parseFloat(number) / 100;
        return (_number * _base) + 'px';
      }
  
      function getViewport() {
        var vh = window.innerHeight;
        var vw = window.innerWidth;
  
        return {
          vh: vh,
          vw: vw,
          vmax: Math.max(vw, vh),
          vmin: Math.min(vw, vh),
        };
      }
  
      function importCrossOriginLinks(next) {
        var _waiting = 0;
        var decrease = function() {
          _waiting--;
          if (!_waiting) {
            next();
          }
        };
  
        forEach.call(document.styleSheets, function(sheet) {
          if (!sheet.href || origin(sheet.href) === origin(location.href) || sheet.ownerNode.getAttribute('data-viewport-units-buggyfill') === 'ignore') {
            // skip <style> and <link> from same origin or explicitly declared to ignore
            return;
          }
  
          _waiting++;
          convertLinkToStyle(sheet.ownerNode, decrease);
        });
  
        if (!_waiting) {
          next();
        }
      }
  
      function origin(url) {
        return url.slice(0, url.indexOf('/', url.indexOf('://') + 3));
      }
  
      function convertLinkToStyle(link, next) {
        getCors(link.href, function() {
          var style = document.createElement('style');
          style.media = link.media;
          style.setAttribute('data-href', link.href);
          style.textContent = this.responseText;
          link.parentNode.replaceChild(style, link);
          next();
        }, next);
      }
  
      function getCors(url, success, error) {
        var xhr = new XMLHttpRequest();
        if ('withCredentials' in xhr) {
          // XHR for Chrome/Firefox/Opera/Safari.
          xhr.open('GET', url, true);
        } else if (typeof XDomainRequest !== 'undefined') {
          // XDomainRequest for IE.
          xhr = new XDomainRequest();
          xhr.open('GET', url);
        } else {
          throw new Error('cross-domain XHR not supported');
        }
  
        xhr.onload = success;
        xhr.onerror = error;
        xhr.send();
        return xhr;
      }
  
      return {
        version: '0.6.1',
        findProperties: findProperties,
        getCss: getReplacedViewportUnits,
        init: initialize,
        refresh: refresh,
      };
    }));
  })();